package cn.iocoder.yudao.framework.handler;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.id.IdUtils;
import cn.iocoder.yudao.framework.handlermapping.NettyWsChannelContext;
import cn.iocoder.yudao.framework.handlermapping.NettyWsHandlerMappingManager;
import cn.iocoder.yudao.framework.message.ClientRequest;
import cn.iocoder.yudao.framework.prometheus.ws.WebSocketMessageMetrics;
import cn.iocoder.yudao.module.infra.util.TraceIdUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class NettyWsRequestDispatcherHandler extends ChannelInboundHandlerAdapter {
    @Resource
    private WebSocketMessageMetrics webSocketMessageMetrics;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ClientRequest) {
            String uri = null;
            try {
                final ClientRequest request = (ClientRequest) msg;
                final NettyWsChannelContext gtx = new NettyWsChannelContext(ctx, request);
                uri = request.getUri();

                TraceIdUtil.setUserId(gtx.getUser().getUserId());
                TraceIdUtil.setTraceId(request.getTraceId());

                webSocketMessageMetrics.recordProcessingMessage(uri);

//                gtx.writeAndFlush(new Object());

                final NettyWsHandlerMappingManager mappingManager = NettyWsHandlerMappingManager.getInstance();
                mappingManager.callMethod(gtx, request);
            } catch (Throwable e) {
                log.error(StrUtil.format("处理客户端请求异常, uri = {}", uri), e);
                webSocketMessageMetrics.recordNettyExceptionMessage(uri);
            }
        } else {
            log.warn("收到非法请求数据, msgClass = {}", msg.getClass().getName());
            ctx.fireChannelRead(msg);
            TraceIdUtil.removeUserId();
            TraceIdUtil.removeTraceId();
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //接收channel内部的一些事件
        if (evt instanceof IdleStateEvent) {
            log.info("连接空闲达到最大时间断开连接, sessionId = {}", ctx.channel().id());
            ctx.channel().close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("服务器内部异常", cause);
    }

}
